package com.invient.math.test;

import junit.framework.TestCase;
import static org.junit.Assert.*;

import com.invient.math.Matrix4f;
import com.invient.math.Vector4f;

public class Matrix4fTest extends TestCase
{
    private static final float DELTA = 0.001f;
    
    public void testConstructor() {
        Matrix4f matrix = new Matrix4f();
        float[] data = matrix.getData();
        assertEquals(data[0], 1.0f);
        assertEquals(data[5], 1.0f);
        assertEquals(data[10], 1.0f);
        assertEquals(data[15], 1.0f);
    }
    
    public void testSetGetData() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f};
        matrix.setData(array);
        float[] out = matrix.getData();
        for ( int i = 0; i < out.length; i++ )
            assertEquals(out[i], array[i]);
    }
    
    public void testIdentity() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f,
                         3.0f, 3.0f, 3.0f, 3.0f};
        matrix.setData(array);
        matrix.identity();
        float[] data = matrix.getData();
        assertEquals(data[0], 1.0f);
        assertEquals(data[5], 1.0f);
        assertEquals(data[10], 1.0f);
        assertEquals(data[15], 1.0f);
    }
    
    public void testSetGet() {
        Matrix4f matrix = new Matrix4f();
        final float value = 7.0f;
        float[] array = {0.0f, 0.0f, 0.0f, value,
                         value, 0.0f, 0.0f, 0.0f,
                         0.0f, 0.0f, value, 0.0f,
                         0.0f, 0.0f, 0.0f, value};
        
        matrix.setData(array);
        float data = matrix.get(1, 0);
        assertEquals(value, data);
        
        data = matrix.get(0, 3);
        assertEquals(value, data);
        
        data = matrix.get(2, 2);
        assertEquals(value, data);
        
        data = matrix.get(3, 3);
        assertEquals(value, data);
    }
    
    public void testGetColumn() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {1.0f, 2.0f, 3.0f, 4.0f,
                         5.0f, 6.0f, 7.0f, 8.0f,
                         9.0f, 10.0f, 11.0f, 12.0f,
                         13.0f, 14.0f, 15.0f, 16.0f};
                         
        matrix.setData(array);
        Vector4f column1 = matrix.getColumn(0);
        assertEquals(1.0f, column1.getW());
        assertEquals(5.0f, column1.getX());
        assertEquals(9.0f, column1.getY());
        assertEquals(13.0f, column1.getZ());
        
        Vector4f column2 = matrix.getColumn(1);
        assertEquals(2.0f, column2.getW());
        assertEquals(6.0f, column2.getX());
        assertEquals(10.0f, column2.getY());
        assertEquals(14.0f, column2.getZ());
        
        Vector4f column3 = matrix.getColumn(2);
        assertEquals(3.0f, column3.getW());
        assertEquals(7.0f, column3.getX());
        assertEquals(11.0f, column3.getY());
        assertEquals(15.0f, column3.getZ());
        
        Vector4f column4 = matrix.getColumn(3);
        assertEquals(4.0f, column4.getW());
        assertEquals(8.0f, column4.getX());
        assertEquals(12.0f, column4.getY());
        assertEquals(16.0f, column4.getZ());
    }
    
    public void testGetRow() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {1.0f, 2.0f, 3.0f, 4.0f,
                         5.0f, 6.0f, 7.0f, 8.0f,
                         9.0f, 10.0f, 11.0f, 12.0f,
                         13.0f, 14.0f, 15.0f, 16.0f};
        
        matrix.setData(array);
        
        Vector4f row1 = matrix.getRow(0);
        assertEquals(1.0f, row1.getW());
        assertEquals(2.0f, row1.getX());
        assertEquals(3.0f, row1.getY());
        assertEquals(4.0f, row1.getZ());
        
        Vector4f row2 = matrix.getRow(1);
        assertEquals(5.0f, row2.getW());
        assertEquals(6.0f, row2.getX());
        assertEquals(7.0f, row2.getY());
        assertEquals(8.0f, row2.getZ());
        
        Vector4f row3 = matrix.getRow(2);
        assertEquals(9.0f, row3.getW());
        assertEquals(10.0f, row3.getX());
        assertEquals(11.0f, row3.getY());
        assertEquals(12.0f, row3.getZ());
        
        Vector4f row4 = matrix.getRow(3);
        assertEquals(13.0f, row4.getW());
        assertEquals(14.0f, row4.getX());
        assertEquals(15.0f, row4.getY());
        assertEquals(16.0f, row4.getZ());
    }
    
    public void testSetRow() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {1.0f, 2.0f, 3.0f, 4.0f,
                         5.0f, 6.0f, 7.0f, 8.0f,
                         9.0f, 10.0f, 11.0f, 12.0f,
                         13.0f, 14.0f, 15.0f, 16.0f};
        
        matrix.setData(array);
        
        Vector4f row1 = new Vector4f(1.0f, 2.0f, 3.0f, 4.0f);
        matrix.setRow(0, row1);
        
        Vector4f row1Test = matrix.getRow(0);
        assertEquals(1.0f, row1Test.getW());
        assertEquals(2.0f, row1Test.getX());
        assertEquals(3.0f, row1Test.getY());
        assertEquals(4.0f, row1Test.getZ());
        
        Vector4f row2 = new Vector4f(5.0f, 6.0f, 7.0f, 8.0f);
        matrix.setRow(1, row2);
        
        Vector4f row2Test = matrix.getRow(1);
        assertEquals(5.0f, row2Test.getW());
        assertEquals(6.0f, row2Test.getX());
        assertEquals(7.0f, row2Test.getY());
        assertEquals(8.0f, row2Test.getZ());
        
        Vector4f row3 = new Vector4f(9.0f, 10.0f, 11.0f, 12.0f);
        matrix.setRow(2, row3);
        
        Vector4f row3Test = matrix.getRow(2);
        assertEquals(9.0f, row3Test.getW());
        assertEquals(10.0f, row3Test.getX());
        assertEquals(11.0f, row3Test.getY());
        assertEquals(12.0f, row3Test.getZ());
        
        Vector4f row4 = new Vector4f(13.0f, 14.0f, 15.0f, 16.0f);
        matrix.setRow(3, row4);
        
        Vector4f row4Test = matrix.getRow(3);
        assertEquals(13.0f, row4Test.getW());
        assertEquals(14.0f, row4Test.getX());
        assertEquals(15.0f, row4Test.getY());
        assertEquals(16.0f, row4Test.getZ());
    }
    
    public void testSetColumn() {
        Matrix4f matrix = new Matrix4f();
        float[] array = {1.0f, 2.0f, 3.0f, 4.0f,
                         5.0f, 6.0f, 7.0f, 8.0f,
                         9.0f, 10.0f, 11.0f, 12.0f,
                         13.0f, 14.0f, 15.0f, 16.0f};
        
        matrix.setData(array);
        
        Vector4f column1 = new Vector4f(1.0f, 5.0f, 9.0f, 13.0f);
        matrix.setColumn(0, column1);
        
        Vector4f column1Test = matrix.getColumn(0);
        assertEquals(1.0f, column1Test.getW());
        assertEquals(5.0f, column1Test.getX());
        assertEquals(9.0f, column1Test.getY());
        assertEquals(13.0f, column1Test.getZ());
        
        Vector4f column2 = new Vector4f(2.0f, 6.0f, 10.0f, 14.0f);
        matrix.setColumn(1, column2);
        
        Vector4f column2Test = matrix.getColumn(1);
        assertEquals(2.0f, column2Test.getW());
        assertEquals(6.0f, column2Test.getX());
        assertEquals(10.0f, column2Test.getY());
        assertEquals(14.0f, column2Test.getZ());
        
        Vector4f column3 = new Vector4f(3.0f, 7.0f, 11.0f, 15.0f);
        matrix.setColumn(2, column3);
        
        Vector4f column3Test = matrix.getColumn(2);
        assertEquals(3.0f, column3Test.getW());
        assertEquals(7.0f, column3Test.getX());
        assertEquals(11.0f, column3Test.getY());
        assertEquals(15.0f, column3Test.getZ());
        
        Vector4f column4 = new Vector4f(4.0f, 8.0f, 12.0f, 16.0f);
        matrix.setColumn(3, column4);
        
        Vector4f column4Test = matrix.getColumn(3);
        assertEquals(4.0f, column4Test.getW());
        assertEquals(8.0f, column4Test.getX());
        assertEquals(12.0f, column4Test.getY());
        assertEquals(16.0f, column4Test.getZ());
    }
    
    public void testMultiply() {
        Matrix4f matrix1 = new Matrix4f();
        Matrix4f matrix2 = new Matrix4f();
        
        float[] array1 = {1.0f, 2.0f, 3.0f, 4.0f,
                         5.0f, 6.0f, 7.0f, 8.0f,
                         9.0f, 10.0f, 11.0f, 12.0f,
                         13.0f, 14.0f, 15.0f, 16.0f};
                         
        float[] array2 = {16.0f, 15.0f, 14.0f, 13.0f,
                         12.0f, 11.0f, 10.0f, 9.0f,
                         8.0f, 7.0f, 6.0f, 5.0f,
                         4.0f, 3.0f, 2.0f, 1.0f};
                         
        float[] actualResult = {80.0f, 70.0f, 60.0f, 50.0f,
                         240.0f, 214.0f, 188.0f, 162.0f,
                         400.0f, 358.0f, 316.0f, 274.0f,
                         560.0f, 502.0f, 444.0f, 386.0f};
                         
        matrix1.setData(array1);
        matrix2.setData(array2);
        
        Matrix4f result = Matrix4f.multiply(matrix1, matrix2);
        float[] resultData = result.getData();
        
        for ( int i = 0; i < actualResult.length; i++ )
            assertEquals(actualResult[i], resultData[i], DELTA);
    }
}